package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.common.auth.domain.Payload;
import com.leyou.common.auth.domain.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.exception.domain.ExceptionEnum;
import com.leyou.common.exception.domain.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.UserDTO;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {

    @Autowired
    private JwtProperties prop;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 认证业务逻辑
     * @param username
     * @param password
     * @param response
     */
    public void login(String username, String password, HttpServletResponse response) {
        //验证用户名和密码是否正确
        UserDTO userDTO = userClient.findByUsernameAndPassword(username, password);
        if(userDTO==null){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //注意，第三个参数现在并没有使用，可以随便写，实战中完善。
        //UserInfo userInfo = new UserInfo(userDTO.getId(), userDTO.getUsername(), "ROLE_ADMIN");
        //创建token并发送到浏览器的cookie中
        //createAndSendTokenToCookie(response, userInfo);
    }

    /**
     * 创建token并发送到浏览器的cookie中
     * @param response
     * @param userInfo
     */
    private void createAndSendTokenToCookie(HttpServletResponse response, UserInfo userInfo) {
        //生成token,三个参数，一：token中的用户信息，二，私钥，三，过期时间
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, prop.getPrivateKey(), prop.getUser().getExpire());
        //写入浏览器Cookie中
        CookieUtils.newCookieBuilder()
                .response(response)
                .name(prop.getUser().getCookieName())
                .value(token)
                .domain(prop.getUser().getCookieDomain())
                .httpOnly(true)
                .build();
    }

    /**
     * yan验证用户登录
     * @param request
     * @param response
     * @return
     */
    public UserInfo verifyLogin(HttpServletRequest request, HttpServletResponse response) {
        //获取名称为LY_TOKEN的Cookie
        String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());
        if(StringUtils.isBlank(token)){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        Payload<UserInfo> payload = null;
        try {
            payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        //获取token的id
        String tokenId = payload.getId();
        //判断当前token是否在redis黑名单中
        if(redisTemplate.hasKey(tokenId)){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        //获取用户信息
        UserInfo userInfo = payload.getUserInfo();
        //获取过期时间
        Date expTime = payload.getExpiration();
        //获取刷新时间
        DateTime refreshTime = new DateTime(expTime).minusMinutes(prop.getUser().getRefreshTime());
        //判断如果刷新时间在当前时间之前，就刷新token
        if(refreshTime.isBefore(System.currentTimeMillis())){
            //创建token并发送到浏览器的cookie中
            createAndSendTokenToCookie(response, userInfo);
        }
        return userInfo;
    }

    /**
     * 退出登录
     * @param request
     */
    public void logout(HttpServletRequest request, HttpServletResponse response){
        //获取token
        String token = CookieUtils.getCookieValue(request, prop.getUser().getCookieName());
        if(StringUtils.isBlank(token)){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        Payload<UserInfo> payload = null;
        try {
            //验证token是否合法
            payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        //获取token的id和过期时间
        String tokenId = payload.getId();
        Date expTime = payload.getExpiration();
        //查看还剩多长时间token过期
        long remainTime = expTime.getTime() - System.currentTimeMillis();
        if(remainTime>1000){
            //放入到redis黑名单中
            redisTemplate.opsForValue().set(tokenId, "1", remainTime, TimeUnit.MILLISECONDS);
        }
        //删除Cookie
        CookieUtils.deleteCookie(prop.getUser().getCookieName(), prop.getUser().getCookieDomain(), response);
    }
}
